package com.cheetah.start.common.shoesImg;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Moments;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ContourContentSimilarity {

    /**
     * 提取轮廓区域的内容特征
     */
    public static ContourFeature extractContourFeature(Mat image, MatOfPoint contour) {
        ContourFeature feature = new ContourFeature();
        feature.contour = contour;

        // 提取轮廓ROI区域
        Mat roi = extractContourROI(image, contour);
        feature.roi = roi;

        // 计算颜色特征
        feature.colorHistogram = computeColorHistogram(roi);

        // 计算纹理特征
        feature.textureFeature = computeTextureFeature(roi);

        // 计算形状特征
        feature.shapeFeature = computeShapeFeature(contour);

        // 计算边缘特征
        feature.edgeFeature = computeEdgeFeature(roi);

        return feature;
    }

    /**
     * 提取轮廓区域ROI
     */
    private static Mat extractContourROI(Mat image, MatOfPoint contour) {
        // 创建轮廓掩码
        Mat mask = Mat.zeros(image.size(), CvType.CV_8UC1);
        List<MatOfPoint> contours = new ArrayList<>();
        contours.add(contour);
        Imgproc.fillPoly(mask, contours, new Scalar(255));

        // 提取ROI
        Mat roi = new Mat();
        image.copyTo(roi, mask);

        // 裁剪到边界框
        Rect rect = Imgproc.boundingRect(contour);
        return new Mat(roi, rect);
    }

    /**
     * 计算颜色直方图特征
     */
    private static Mat computeColorHistogram(Mat roi) {
        Mat hsv = new Mat();
        Imgproc.cvtColor(roi, hsv, Imgproc.COLOR_BGR2HSV);

        // 创建非黑色掩码（排除背景）
        Mat mask = createNonBlackMask(roi);

        // 计算HSV三通道直方图
        Mat histH = new Mat(), histS = new Mat(), histV = new Mat();

        // H通道（色调）
        Imgproc.calcHist(Arrays.asList(hsv), new MatOfInt(0), mask, histH,
                new MatOfInt(30), new MatOfFloat(0, 180));

        // S通道（饱和度）
        Imgproc.calcHist(Arrays.asList(hsv), new MatOfInt(1), mask, histS,
                new MatOfInt(32), new MatOfFloat(0, 256));

        // V通道（亮度）
        Imgproc.calcHist(Arrays.asList(hsv), new MatOfInt(2), mask, histV,
                new MatOfInt(32), new MatOfFloat(0, 256));

        // 归一化
        Core.normalize(histH, histH, 1, 0, Core.NORM_L2);
        Core.normalize(histS, histS, 1, 0, Core.NORM_L2);
        Core.normalize(histV, histV, 1, 0, Core.NORM_L2);

        // 合并特征向量
        Mat colorFeature = new Mat();
        Core.hconcat(Arrays.asList(
                histH.reshape(1, 1),
                histS.reshape(1, 1),
                histV.reshape(1, 1)
        ), colorFeature);

        return colorFeature;
    }

    /**
     * 计算纹理特征（LBP）
     */
    private static Mat computeTextureFeature(Mat roi) {
        Mat gray = new Mat();
        Imgproc.cvtColor(roi, gray, Imgproc.COLOR_BGR2GRAY);

        // 计算LBP纹理
        Mat lbp = computeLBP(gray);

        // 计算LBP直方图
        Mat lbpHist = new Mat();
        Imgproc.calcHist(Arrays.asList(lbp), new MatOfInt(0), new Mat(),
                lbpHist, new MatOfInt(16), new MatOfFloat(0, 256));
        Core.normalize(lbpHist, lbpHist, 1, 0, Core.NORM_L2);

        return lbpHist.reshape(1, 1);
    }

    /**
     * 计算形状特征
     */
    private static Mat computeShapeFeature(MatOfPoint contour) {
        Mat shapeFeature = new Mat(1, 6, CvType.CV_32F);

        // 基础形状特征
        double area = Imgproc.contourArea(contour);
        double perimeter = Imgproc.arcLength(new MatOfPoint2f(contour.toArray()), true);
        Rect rect = Imgproc.boundingRect(contour);
        double aspectRatio = (double) rect.width / rect.height;

        // 圆形度
        double circularity = (4 * Math.PI * area) / (perimeter * perimeter);

        // Hu矩（形状描述符）
        MatOfPoint2f contour2f = new MatOfPoint2f(contour.toArray());
        Moments moments = Imgproc.moments(contour2f);
        Mat huMoments = new Mat();
        Imgproc.HuMoments(moments, huMoments);

        // 填充特征向量
        shapeFeature.put(0, 0, area);
        shapeFeature.put(0, 1, perimeter);
        shapeFeature.put(0, 2, aspectRatio);
        shapeFeature.put(0, 3, circularity);
        shapeFeature.put(0, 4, huMoments.get(0, 0)[0]);
        shapeFeature.put(0, 5, huMoments.get(1, 0)[0]);

        // 归一化
        Core.normalize(shapeFeature, shapeFeature, 1, 0, Core.NORM_L2);

        return shapeFeature;
    }

    /**
     * 计算边缘特征
     */
    private static Mat computeEdgeFeature(Mat roi) {
        Mat gray = new Mat();
        Imgproc.cvtColor(roi, gray, Imgproc.COLOR_BGR2GRAY);

        Mat edges = new Mat();
        Imgproc.Canny(gray, edges, 50, 150);

        // 计算边缘方向直方图
        Mat orientationHist = new Mat();
        Imgproc.calcHist(Arrays.asList(edges), new MatOfInt(0), new Mat(),
                orientationHist, new MatOfInt(8), new MatOfFloat(0, 256));
        Core.normalize(orientationHist, orientationHist, 1, 0, Core.NORM_L2);

        return orientationHist.reshape(1, 1);
    }

    /**
     * 计算LBP纹理
     */
    private static Mat computeLBP(Mat gray) {
        Mat lbp = new Mat(gray.size(), CvType.CV_8UC1);

        for (int i = 1; i < gray.rows() - 1; i++) {
            for (int j = 1; j < gray.cols() - 1; j++) {
                double center = gray.get(i, j)[0];
                byte code = 0;

                code |= (gray.get(i - 1, j - 1)[0] > center ? 1 : 0) << 7;
                code |= (gray.get(i - 1, j)[0] > center ? 1 : 0) << 6;
                code |= (gray.get(i - 1, j + 1)[0] > center ? 1 : 0) << 5;
                code |= (gray.get(i, j + 1)[0] > center ? 1 : 0) << 4;
                code |= (gray.get(i + 1, j + 1)[0] > center ? 1 : 0) << 3;
                code |= (gray.get(i + 1, j)[0] > center ? 1 : 0) << 2;
                code |= (gray.get(i + 1, j - 1)[0] > center ? 1 : 0) << 1;
                code |= (gray.get(i, j - 1)[0] > center ? 1 : 0);

                lbp.put(i, j, code);
            }
        }

        return lbp;
    }

    private static Mat createNonBlackMask(Mat image) {
        Mat mask = new Mat();
        Core.inRange(image, new Scalar(1, 1, 1), new Scalar(255, 255, 255), mask);
        return mask;
    }
}

/**
 * 轮廓特征类
 */
class ContourFeature {
    MatOfPoint contour;
    Mat roi;
    Mat colorHistogram;
    Mat textureFeature;
    Mat shapeFeature;
    Mat edgeFeature;
}
